function aiChoice(round, playerId) {
	const roundWind = round.roundWind
	const seatWind = round.players[playerId].seatWind
	let bestScore = [-99, 0], bestChoice = [], hasTenpai = false
	for (let id = 0; id < playerCount; ++id) {
		if (id !== playerId && !round.players[id].hu && (round.players[id].hand.riichi || (round.players[id].hand.melds.length >= 2 && round.players[id].hand.melds.some(meld => (meld[1] & 3) === 3)))) {
			hasTenpai = true
			break
		}
	}
	for (const choice of round.players[playerId].choices) {
		const typ = choice[0]
		if (typ === CHOICE_HU || typ === CHOICE_TSUMO || typ === CHOICE_RYUUKYOKU) {
			return choice
		}
		if (typ === CHOICE_ADDED_KONG) {
			continue
		}

		let hand = structuredClone(round.players[playerId].hand)
		if (typ) {
			if (typ === CHOICE_DISCARD) {
				removeElementFromArray(hand.tiles, choice[1])
			} else if (typ === CHOICE_RIICHI) {
				removeElementFromArray(hand.tiles, choice[1])
				hand.riichi = true
			} else {
				for (const tile of choice[3]) {
					removeElementFromArray(hand.tiles, tile)
				}
				hand.melds.push(structuredClone(choice))
			}
		}

		let counter = newTileCounter()
		countTileArray(counter, hand.tiles)
		for (let i = 0; i < playerCount; ++i) {
			countTileMelds(counter, round.players[i].hand.melds)
			countTileArray(counter, round.players[i].discard)
		}

		const s = shanten(hand, roundWind, seatWind)
		let score2

		if (hasTenpai && s >= (round.dealer === playerId ? 2 : 1)) {
			// AI decides to fold
			if (typ === CHOICE_DISCARD) {
				score2 = 0
				const tile = choice[1], value = getTileValue(tile)
				for (let id = 0; id < playerCount; ++id) {
					if (id !== playerId && !round.players[id].hu) {
						let safetyScore, m = false, l = false, r = false
						for (const discard in round.players[id].discard) {
							const v = getTileValue(discard)
							if (v === value) {
								m = true
								break
							} else if ((value & 3) !== 3) {
								if (v === value - 12) {
									l = true
								} else if (v === value + 12) {
									r = true
								}
							}
						}
						if (m) {
							// Genbutsus are 100% safe
							safetyScore = 14
						} else if ((value & 3) === 3) {
							// Honor tiles are relatively more safe
							safetyScore = [13, 12, 10, 9, 9][counter[value]]
						} else if ((value >> 2) >= 4 && (value >> 2) <= 6) {
							// 456 tiles are most dangerous
							safetyScore = (l ? (r ? 8 : 6) : (r ? 6 : 0))
						} else {
							// Number tiles are relatively dangerous
							if ((r && (value >> 2) === 1) || (l && (value >> 2) === 9)) {
								safetyScore = 11
							} else if (l || r) {
								safetyScore = 8
							} else {
								safetyScore = 6
							}
						}
						// Tiles near dora are more dangerous
						for (let i = 0; i < round.doraCount; ++i) {
							const dora = getTileValue(round.wanpai[i * 2])
							if (value === dora) {
								if ((dora & 3) === 3 || ((dora >> 2) === 1 || (dora >> 2) === 9)) {
									// Yaochuu doras are even more dangerous
									safetyScore -= 3
								} else {
									safetyScore -= 2
								}
							} else if ((dora & 3) !== 3 && !((dora ^ value) & 3) && Math.abs(value - dora) < 14) {
								safetyScore -= 1
							}
						}
						// Akadoras are more dangerous
						if (tile & TILE_AKA) {
							safetyScore -= 2
						}
						score2 += (round.players[id].hand.riichi ? 2 : 1) * (safetyScore >= 1 ? safetyScore : 1)
					}
				}
			} else if (typ === CHOICE_NONE) {
				score2 = 0
			} else {
				score2 = -1
			}
		} else {
			// AI decides to push
			function dfs(depth, s, lastDraw) {
				if (!depth) {
					const h = hu(hand, false, lastDraw,
						round.roundWind,
						round.players[playerId].seatWind,
						round.wanpai, round.doraCount)
					return h ? (h.points + 1) : 1
				}
				let ans = 0
				for (let suit = 0; suit < 4; ++suit) {
					for (let tile = (suit === 3 ? 31 : (36 | suit)); tile > 3; tile -= 4)if (counter[tile] > 0) {
						const c = (counter[tile]--)
						hand.tiles.push(tile)

						if (hu(hand, false, tile,
							round.roundWind,
							round.players[playerId].seatWind,
							round.wanpai, round.doraCount) || shantenLessThan(hand, s, roundWind, seatWind))
							ans += c * dfs(depth - 1, s - 1, tile)

						removeElementFromArray(hand.tiles, tile)
						++counter[tile]
					}
				}
				return ans
			}
			score2 = dfs((s < aiDepth) ? (s + 1) : aiDepth, s) * 2 - (hand.riichi ? 1 : 0)
		}
		const score = [-s, score2]
		if (bestScore[0] < score[0] || (bestScore[0] === score[0] && bestScore[1] < score[1])) {
			bestScore = score
			bestChoice = [choice]
		} else if (bestScore[0] === score[0] && bestScore[1] === score[1]) {
			bestChoice.push(choice)
		}
	}
	if (!bestChoice.length) {
		bestChoice = round.players[playerId].choices
	}
	return bestChoice[Math.floor(Math.random() * bestChoice.length)]
}